﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Objects;
using BusinessBingo.Common.Interfaces;
using BusinessBingo.Data.DataLoadOptions;
using BusinessBingo.Data.DataOrderOptions;
using BusinessBingo.Data.Filter;
using BusinessBingo.Data.Interfaces;
using BusinessBingo.Model;

namespace BusinessBingo.Data
{
    public class EFBingoSetRepository : EFBaseRepository, IBingoSetRepository
    {
        public EFBingoSetRepository(IUnitOfWork unitOfWork, IGuid portalGuid)
            : base(unitOfWork, portalGuid)
        {
        }

        public IList<Model.BingoSet> GetItems(BingoSetDataLoadOptions dlo, BingoSetDataOrderOptions doo, BingoSetFilter filter)
        {
            ObjectQuery<BingoSet> query = this.GetQuery(dlo, doo, filter);
            List<BingoSet> items = query.ToList();

            IList<Model.BingoSet> result = Mapping.MapBingoSets(items);

            return result;
        }

        public void AddItem(Model.BingoSet bingoSet)
        {
            BingoSet bs = new BingoSet();
            bs.Id = this._portalGuid.New;
            bs.GameId = bingoSet.GameId;
            bs.SessionUserId = bingoSet.UserId;
            this._context.AddToBingoSets(bs);

            foreach(WordPosition wordPosition in bingoSet.WordPositions)
            {
                BingoWordSet bingoWordSet = new BingoWordSet();
                bingoWordSet.Id = this._portalGuid.New;
                bingoWordSet.WordPositionX = wordPosition.PositionX;
                bingoWordSet.WordPositionY = wordPosition.PositionY;
                bingoWordSet.WordId = wordPosition.Word.Id;
                bingoWordSet.Checked = wordPosition.Checked;
                bingoWordSet.BingoSetId = bs.Id;
                
                this._context.AddToBingoWordSets(bingoWordSet);
            }
        }

        public void CheckWord(Guid userId, Guid gameId, Guid wordId)
        {
            BingoSet bingoSet = (from x in this._context.BingoSets
                                 where x.SessionUserId.Equals(userId) && x.GameId.Equals(gameId)
                                 select x).ToList().Single();

            BingoWordSet bingoWordSet = (from b in this._context.BingoWordSets
                                         where b.BingoSetId.Equals(bingoSet.Id) && b.WordId.Equals(wordId)
                                         select b).ToList().Single();
            bingoWordSet.Checked = true;
        }

        public ObjectQuery<Data.BingoSet> GetQuery(BingoSetDataLoadOptions dlo, BingoSetDataOrderOptions doo, BingoSetFilter filter)
        {
            ObjectQuery<BingoSet> query = this._context.BingoSets;

            return query.LoadWith(dlo).FilterFor(filter).OrderBy(doo);
        }

        public int GetItemsCount(BingoSetFilter filter)
        {
            ObjectQuery<BingoSet> query = this.GetQuery(null, null, filter);
            return query.Count();
        }
    }

    internal static class BingoSetQueryExtensions
    {
        public static ObjectQuery<BingoSet> FilterFor(this ObjectQuery<BingoSet> query, BingoSetFilter filter)
        {
            if (filter == null) return query;

            if (filter.WithUserId.HasValue == true)
                query = (ObjectQuery<BingoSet>) query.Where(a => a.SessionUserId == filter.WithUserId.Value);
            
            if(filter.WithGameId.HasValue == true)
                query = (ObjectQuery<BingoSet>)query.Where(a => a.GameId == filter.WithGameId.Value);

            return query;
        }

        public static ObjectQuery<BingoSet> LoadWith(this ObjectQuery<BingoSet> query, BingoSetDataLoadOptions dlo)
        {
            BingoSetDataLoadOptions bdlo = (BingoSetDataLoadOptions)dlo;

            if (bdlo == null) return query;

            if (bdlo.LoadWithWordPositions == true)
                query = query.Include("BingoWordSets");

            return query;
        }

        public static ObjectQuery<BingoSet> OrderBy(this ObjectQuery<BingoSet> query, BingoSetDataOrderOptions doo)
        {
            return query;
        }
    }
}